package com.beiding.hotcode.v2;

import java.io.File;
import java.util.*;


class HotPackage implements MyPackage {

    private Set<String> allClasses = new HashSet<>();

    private File packageFile;

    Map<String, JavaMonitor> javaMonitorMap = new HashMap<>();


    //包名,可以从该包下面获取  MyClass
    private String name;

    MyFactory myFactory;

    private HotPackage() {

    }

    public MyClass getMyClassBySimpleName(String name) {
        return getMyClass(this.name + "." + name);
    }

    //获取响应的class
    public MyClass getMyClass(String name) {

        if (!name.startsWith(this.name + ".")) {
            throw new RuntimeException("无法获取");
        }

        //获取之前先进行一次检查
   /*     if (this.monitorGroup.checkChange()) {
            this.monitorGroup.reloadClass();
        }*/

        return myFactory.getMyClass(name);
    }

    @Override
    public <TYPE> MyClass<TYPE> getMyClass(Class<TYPE> type) {
        return getMyClass(type.getName());
    }

    static HotPackage create(MyFactory myFactory, String name) {
        HotPackage myPackage = new HotPackage();

        myPackage.myFactory = myFactory;

        myPackage.name = name;

        //重写相关逻辑
        myPackage.monitorGroup = new MonitorGroup(myFactory) {
            @Override
            boolean checkChange() {//扫描的时候应该只处理一次就可以

                Set<String> set = myPackage.scanJavaFile();
                if (!set.equals(myPackage.allClasses)) {
                    Set<String> willRemove = new HashSet<>(myPackage.allClasses);
                    willRemove.removeAll(set);

                    for (String s : willRemove) {
                        JavaMonitor remove = myPackage.javaMonitorMap.remove(s);
                        remove(remove);
                    }

                    Set<String> willAdd = new HashSet<>(set);
                    willAdd.removeAll(myPackage.allClasses);
                    for (String s : willAdd) {
                        JavaMonitor javaMonitor = myFactory.getMonitor(s);
                        myPackage.javaMonitorMap.put(s, javaMonitor);
                        //System.out.println("创建:" + s);
                        add(javaMonitor);
                    }
                    myPackage.allClasses = set;
                }

                return super.checkChange();
            }

        };


        myPackage.packageFile = new File(myFactory.hotCodeConfig.getSrcRoot(), name.replace(".", File.separator));

        myPackage.monitorGroup.checkChange();
        /*if (myPackage.monitorGroup.checkChange()) {
            myPackage.monitorGroup.reloadClass();
        }*/

        return myPackage;
    }

    MonitorGroup monitorGroup;

    private Set<String> scan(File pf, String prefix) {

        File[] files = pf.listFiles();
        if (files != null) {
            Set<String> all = new HashSet<>();
            for (File file : files) {
                if (file.isFile()) {
                    String name = file.getName();
                    if (name.endsWith(".java")) {
                        name = name.substring(0, name.length() - 5);
                        all.add(prefix + "." + name);
                    }
                } else if (file.isDirectory()) {

                    Set<String> scan = scan(file, prefix + "." + file.getName());
                    all.addAll(scan);
                }
            }
            return all;
        } else {
            return Collections.emptySet();
        }
    }

    Set<String> scanJavaFile() {
        return scan(packageFile, name);
    }

    @Override
    public boolean equals(Object obj) {
        if (!(obj instanceof HotPackage)) {
            return false;
        }

        return this.name.equals(((HotPackage) obj).name) && ((HotPackage) obj).myFactory == this.myFactory;
    }

    @Override
    public int hashCode() {
        return name.hashCode();
    }

    boolean include(HotPackage hotPackage) {
        return hotPackage.name.startsWith(this.name + ".");
    }


}
